%%% @doc
%%% окно для запуска тестов
%%% @end
-module(server_ui).
-export([event_loop/3, create_window/2]).
-include_lib("wx/include/wx.hrl").
-include("definitions.hrl").

%% constants
-define(BUTTON_START, 1).
-define(BUTTON_START_AUTO, 2).
-define(BUTTON_OPEN_EDITOR, 3).
-define(GRID_DEVICES, 4).
-define(GRID_TESTS, 5).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% на экспорт
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-spec event_loop/3 :: (wxFrame:wxFrame(), wxGrid:wxGrid(), [device()]) -> 'ok' | {'error', Reason} when Reason :: term().
event_loop(WxFrame, GridDevices, DeviceList) ->
  receive

    #wx{event = #wxClose{}} ->
      true = wxFrame:close(WxFrame),
      server_logic:dispose();

    #wx{id = ?BUTTON_OPEN_EDITOR, event = #wxCommand{type = command_button_clicked}} ->
      open_editor(),
      event_loop(WxFrame, GridDevices, DeviceList);

    #wx{id = ?BUTTON_START_AUTO, event = #wxCommand{type = command_button_clicked}} ->
      {ok, Count} = application:get_env(devices_limit),
      server_logic:show_tests(Count),%length(DeviceList)
      {DevList, Tests} = server_logic:prepare_tests_auto(),
      {ok, testsRunning} = server_logic:run_tests(DevList, Tests),
      event_loop(WxFrame, GridDevices, DeviceList);


    #wx{id = ?BUTTON_START, event = #wxCommand{type = command_button_clicked}} ->
      Tests = get_tests_from_grid(GridDevices, length(DeviceList), dict:new()),
      {ok, testsRunning} = server_logic:run_tests(DeviceList, Tests),
      server_logic:show_tests(length(DeviceList)),
      event_loop(WxFrame, GridDevices, DeviceList);

    {'DOWN', _, process, Pid, Reason} ->%my_ping fell
      io:format("~p ping ~p fell of ~p ~n", [?MODULE, Pid, Reason]),
      true = wxFrame:close(WxFrame),
      event_loop(WxFrame, GridDevices, DeviceList)
%%       server_logic:dispose()
  end.

open_editor() ->
  ok.

%% -spec create_window/2 :: ([device()], [integer()]) -> {{'wx_ref', integer(), _, _}, {'wx_ref', integer(), _, _}}.
-spec create_window/2 :: ([device()], [test_id()]) -> {wxFrame:wxFrame(), wxGrid:wxGrid()}.
create_window(DeviceList, TestIds) when is_list(TestIds) ->
  Wx = wx:new(),
  WxFrame = wxFrame:new(Wx, -1, "Главный экран"),
  wxFrame:setSize(WxFrame, {1000, 620}),
  wxFrame:connect(WxFrame, close_window),
  GridDevices = initControls(WxFrame, DeviceList, TestIds),
  wxFrame:show(WxFrame),
  {WxFrame, GridDevices}.

-spec initControls/3 :: (wxFrame:wxFrame(), [device()], [test_id()]) -> wxGrid:wxGrid().
initControls(WxFrame, DeviceList, TestIds) when is_list(TestIds) ->
  init_buttons(WxFrame),
  create_grid_tests(WxFrame, TestIds),
  create_grid_devices(WxFrame, DeviceList, TestIds).

-spec init_buttons/1 :: (wxFrame:wxFrame()) -> ok.
init_buttons(WxFrame) ->
  ButtonRun = wxButton:new(WxFrame, ?BUTTON_START, [{label, "Запуск выбранных"}, {pos, {50, 530}}, {size, {270, 30}}]),

  {ok, Count} = application:get_env(devices_limit),
  Text = "Запустить " ++ integer_to_list(Count) ++ " тестов",
  ButtonRunAuto = wxButton:new(WxFrame, ?BUTTON_START_AUTO, [{label, Text}, {pos, {360, 530}}, {size, {270, 30}}]),

  ButtonEdit = wxButton:new(WxFrame, ?BUTTON_OPEN_EDITOR, [{label, "Открыть редактор тестов"}, {pos, {670, 530}}, {size, {270, 30}}]),

  ok = wxFrame:connect(ButtonRun, command_button_clicked),
  ok = wxFrame:connect(ButtonEdit, command_button_clicked),
  ok = wxFrame:connect(ButtonRunAuto, command_button_clicked).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% гриды
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-spec create_grid_tests/2 :: (wxFrame:wxFrame(), [test_id()]) -> wxGrid:wxGrid().
create_grid_tests(WxFrame, TestIds) when is_list(TestIds) ->
  Grid = wxGrid:new(WxFrame, ?GRID_TESTS, [{size, {510, 490}}, {pos, {460, 20}}]),
  Rows = length(TestIds),
  Columns = 4,
  wxGrid:createGrid(Grid, Rows, Columns),
  wxGrid:autoSizeRows(Grid),
  wxGrid:autoSizeColumns(Grid),
  wxGrid:setColSize(Grid, 0, 80), %id теста
  wxGrid:setColSize(Grid, 1, 80), %имя прибора
  wxGrid:setColSize(Grid, 2, 170), %прибор
  wxGrid:setColSize(Grid, 3, 80), %прибор
  wxGrid:setColLabelValue(Grid, 0, "id теста"),
  wxGrid:setColLabelValue(Grid, 1, "описание"),
  wxGrid:setColLabelValue(Grid, 2, "предназначен для прибора"),
  wxGrid:setColLabelValue(Grid, 3, "длина"),
  ok = bind_grid_tests(Grid, TestIds, Rows),
  Grid.

-spec bind_grid_tests/3 :: (wxGrid:wxGrid(), [test_id()], non_neg_integer()) -> ok.
bind_grid_tests(_, _, 0) -> ok;

bind_grid_tests(Grid, [TestId | TestIds], N) when is_integer(TestId) and is_integer(N) ->
  Test = storage:get_test(TestId),

  wxGrid:setCellValue(Grid, {N - 1, 0}, integer_to_list(Test#testCase.id)),
  wxGrid:setCellValue(Grid, {N - 1, 1}, Test#testCase.description),
  wxGrid:setCellValue(Grid, {N - 1, 2}, integer_to_list(Test#testCase.deviceId)),
  wxGrid:setCellValue(Grid, {N - 1, 3}, integer_to_list(Test#testCase.dataFieldLen)),
  bind_grid_tests(Grid, TestIds, N - 1).

%грид с приборами
-spec create_grid_devices/3 :: (WxFrame, DeviceList, TestIds) -> wxGrid:wxGrid()
  when
  WxFrame :: wxFrame:wxFrame(),
  DeviceList :: list(device()),
  TestIds :: list(test_id()).
create_grid_devices(WxFrame, DeviceList, TestIds) ->
  Grid = wxGrid:new(WxFrame, ?GRID_DEVICES, [{size, {390, 490}}, {pos, {20, 20}}]),
  Rows = length(DeviceList),
  Columns = 3,
  wxGrid:createGrid(Grid, Rows, Columns),
  wxGrid:autoSizeRows(Grid),
  wxGrid:autoSizeColumns(Grid),
  wxGrid:setColSize(Grid, 0, 80), %id прибора
  wxGrid:setColSize(Grid, 1, 80), %имя прибора
  wxGrid:setColSize(Grid, 2, 120), %тест
  wxGrid:setColLabelValue(Grid, 0, "id прибора"),
  wxGrid:setColLabelValue(Grid, 1, "описание"),
  wxGrid:setColLabelValue(Grid, 2, "назначенный тест"),
  CurrentRow = 0,
  ok = bind_grid(Grid, DeviceList, TestIds, CurrentRow),
  Grid.

%если все приборы перечислены
-spec bind_grid/4 :: (wxGrid:wxGrid(), [device()], [test_id()], integer()) -> ok.
bind_grid(_, [], _, _) ->
  ok;

bind_grid(Grid, [Descr | T], TestIds, Row) ->
  Name = Descr#deviceDescriptor.description,
  Id = Descr#deviceDescriptor.id,
  wxGrid:setCellValue(Grid, {Row, 0}, integer_to_list(Id)),
  wxGrid:setCellValue(Grid, {Row, 1}, Name),
  bind_grid(Grid, T, TestIds, Row + 1).

%пройтись по всем строчкам, собрать номера тестов
-spec get_tests_from_grid/3 :: (wxGrid:wxGrid(), Row, OldAcc) -> Acc
  when
  Row :: non_neg_integer(),
  OldAcc :: dict:dict(device_id(), test_id()),
  Acc :: dict:dict(device_id(), test_id()).

get_tests_from_grid(_, 0, Acc) ->
  Acc;

get_tests_from_grid(Grid, N, Acc) ->
  DeviceId = list_to_integer(wxGrid:getCellValue(Grid, {N - 1, 1})),%id прибора
  case wxGrid:getCellValue(Grid, {N - 1, 2}) of%id теста
    [] -> get_tests_from_grid(Grid, N - 1, Acc);
    Number ->
      {TestIdInt, _} = string:to_integer(Number),
      Dict = dict:store(DeviceId, TestIdInt, Acc),
      get_tests_from_grid(Grid, N - 1, Dict)
  end.